﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Utility.DataStructure
{
	public class BijectionMap<TKey, TValue> :
		ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>,
		IEnumerable, ICollection
	{
		Dictionary<TKey, TValue> forwardDict = new Dictionary<TKey, TValue> ();
		Dictionary<TValue, TKey> backwardDict = new Dictionary<TValue, TKey> ();

		public int Count
		{
			get
			{
				return ((ICollection<KeyValuePair<TKey, TValue>>)forwardDict).Count;
			}
		}

		public bool IsReadOnly
		{
			get
			{
				return ((ICollection<KeyValuePair<TKey, TValue>>)forwardDict).IsReadOnly;
			}
		}

		public object SyncRoot
		{
			get
			{
				return ((ICollection)forwardDict).SyncRoot;
			}
		}

		public bool IsSynchronized
		{
			get
			{
				return ((ICollection)forwardDict).IsSynchronized;
			}
		}

		public ICollection Keys
		{
			get
			{
				return forwardDict.Keys;
			}
		}

		public ICollection Values
		{
			get
			{
				return forwardDict.Values;
			}
		}

		public void Add (KeyValuePair<TKey, TValue> item)
		{
			KeyValuePair<TValue, TKey> _item = new KeyValuePair<TValue, TKey> (item.Value, item.Key);
			((ICollection<KeyValuePair<TKey, TValue>>)forwardDict).Add (item);
			((ICollection<KeyValuePair<TValue, TKey>>)backwardDict).Add (_item);
		}

		public void Clear ()
		{
			forwardDict.Clear ();
			backwardDict.Clear ();
		}

		public bool Contains (KeyValuePair<TKey, TValue> item)
		{
			return ((ICollection<KeyValuePair<TKey, TValue>>)forwardDict).Contains (item);
		}

		public void CopyTo (KeyValuePair<TKey, TValue>[] array, int arrayIndex)
		{
			((ICollection<KeyValuePair<TKey, TValue>>)forwardDict).CopyTo (array, arrayIndex);
		}

		public bool Remove (KeyValuePair<TKey, TValue> item)
		{
			KeyValuePair<TValue, TKey> _item = new KeyValuePair<TValue, TKey> (item.Value, item.Key);
			return ((ICollection<KeyValuePair<TKey, TValue>>)forwardDict).Remove (item) && ((ICollection<KeyValuePair<TValue, TKey>>)backwardDict).Remove (_item);
		}

		public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator ()
		{
			return ((ICollection<KeyValuePair<TKey, TValue>>)forwardDict).GetEnumerator ();
		}

		IEnumerator IEnumerable.GetEnumerator ()
		{
			return ((ICollection<KeyValuePair<TKey, TValue>>)forwardDict).GetEnumerator ();
		}

		public void CopyTo (Array array, int index)
		{
			((ICollection)forwardDict).CopyTo (array, index);
		}

		public bool ContainsKey (TKey key)
		{
			return forwardDict.ContainsKey (key);
		}

		public bool ContainsValue (TValue value)
		{
			return backwardDict.ContainsKey (value);
		}

		public bool ContainsBijection (TKey key, TValue value)
		{
			return ContainsKey (key) && forwardDict[key].Equals (value);
		}

		public bool Contains (TKey key, TValue value)
		{
			return ContainsKey (key) || ContainsValue (value);
		}

		public void Add (TKey key, TValue value)
		{
			forwardDict.Add (key, value);
			backwardDict.Add (value, key);
		}

		public void RemoveKey (TKey key)
		{
			backwardDict.Remove (forwardDict[key]);
			forwardDict.Remove (key);
		}

		public void RemoveValue (TValue value)
		{
			forwardDict.Remove (backwardDict[value]);
			backwardDict.Remove (value);
		}

		public TKey GetKey (TValue value)
		{
			return backwardDict[value];
		}

		public TValue GetValue (TKey key)
		{
			return forwardDict[key];
		}

		public bool TryGetKey (TValue value, out TKey key)
		{
			return backwardDict.TryGetValue (value, out key);
		}

		public bool TryGetValue (TKey key, out TValue value)
		{
			return forwardDict.TryGetValue (key, out value);
		}
	}
}